package com.qdhh.enrollment.util;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qdhh.enrollment.common.BusinessException;
import com.qdhh.enrollment.config.WeChatProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.URI;

/**
 * Utility for interacting with WeChat mini program authentication APIs.
 */
@Component
public class WeChatUtil {

    private static final Logger log = LoggerFactory.getLogger(WeChatUtil.class);
    private static final String JSCODE2SESSION_URL = "https://api.weixin.qq.com/sns/jscode2session";

    private final RestTemplate restTemplate;
    private final WeChatProperties weChatProperties;
    private final ObjectMapper objectMapper;

    public WeChatUtil(RestTemplate restTemplate, WeChatProperties weChatProperties, ObjectMapper objectMapper) {
        this.restTemplate = restTemplate;
        this.weChatProperties = weChatProperties;
        this.objectMapper = objectMapper;
    }

    /**
     * Exchange temporary jsCode for openid/session_key.
     *
     * @param jsCode login credential from mini program
     * @return openid string
     */
    public String getOpenId(String jsCode) {
        return getSession(jsCode).getOpenId();
    }

    /**
     * Exchange temporary jsCode for openid/session_key/unionid.
     *
     * @param jsCode login credential from mini program
     * @return session info containing openid and optional unionid
     */
    public WeChatSessionInfo getSession(String jsCode) {
        if (!StringUtils.hasText(jsCode)) {
            throw new BusinessException("缺少 jsCode 参数");
        }
        // 允许开发模式下跳过微信凭证检查（使用 DEV_ 前缀的code）
        if (jsCode.startsWith("DEV_")) {
            log.debug("Dev mode: skipping WeChat credential check");
            return new WeChatSessionInfo("dev_openid_" + jsCode, null);
        }
        if (!StringUtils.hasText(weChatProperties.getAppId()) || !StringUtils.hasText(weChatProperties.getSecret())) {
            log.warn("WeChat credentials not configured, appId: {}, secret: {}", 
                weChatProperties.getAppId() != null ? "set" : "null",
                weChatProperties.getSecret() != null ? "set" : "null");
            throw new BusinessException("未配置微信小程序凭证");
        }

        URI uri = UriComponentsBuilder.fromHttpUrl(JSCODE2SESSION_URL)
            .queryParam("appid", weChatProperties.getAppId())
            .queryParam("secret", weChatProperties.getSecret())
            .queryParam("js_code", jsCode)
            .queryParam("grant_type", "authorization_code")
            .build(true)
            .toUri();

        ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class);
        if (!response.getStatusCode().is2xxSuccessful() || response.getBody() == null) {
            log.warn("WeChat API request failed, status: {}", response.getStatusCode());
            throw new BusinessException("微信登录服务异常");
        }
        try {
            JsonNode jsonNode = objectMapper.readTree(response.getBody());
            if (jsonNode.hasNonNull("errcode") && jsonNode.get("errcode").asInt() != 0) {
                String errMsg = jsonNode.hasNonNull("errmsg") ? jsonNode.get("errmsg").asText() : "微信返回错误";
                log.warn("WeChat API responded with error: {}", errMsg);
                throw new BusinessException(errMsg);
            }
            JsonNode openIdNode = jsonNode.get("openid");
            if (openIdNode == null || !StringUtils.hasText(openIdNode.asText())) {
                throw new BusinessException("未获取到 openid");
            }
            String openId = openIdNode.asText();
            String unionId = jsonNode.hasNonNull("unionid") ? jsonNode.get("unionid").asText() : null;
            return new WeChatSessionInfo(openId, StringUtils.hasText(unionId) ? unionId : null);
        } catch (Exception ex) {
            log.error("Failed to parse WeChat response", ex);
            throw new BusinessException("解析微信返回信息失败");
        }
    }

    public static class WeChatSessionInfo {
        private final String openId;
        private final String unionId;

        public WeChatSessionInfo(String openId, String unionId) {
            this.openId = openId;
            this.unionId = unionId;
        }

        public String getOpenId() {
            return openId;
        }

        public String getUnionId() {
            return unionId;
        }
    }
}
